<template>
  <ListPage
    :search-list="treeSelectSearchList"
    ref="ListPageRef"
  >
    <template #search="{getList,resetGetList}">
      <DynamicForm
        v-model="searchData"
        search
        :form-config-list="formConfigList"
        label-suffix="："
        @search="getList"
        ref="DynamicFormRef"
      >
        <el-form-item v-if="formConfigList.length > 0">
          <el-button
            type="primary"
            @click="getList">搜索</el-button>
          <el-button @click="reset">重置</el-button>
        </el-form-item>
      </DynamicForm>
    </template>
    <template #list="{listData,listHeight,loading}">
      <div class="TableSelect">
        <div class="left">
          <DynamicTable
            :data="getTableListData(listData)"
            :height="listHeight"
            :table-config-list="computedTableConfigList"
            :created-init-value="false"
            ref="leftTableRef"
            @select-change-event="leftSelectChangeEvent"
            @row-update-event="leftRowUpdateEvent"
          >
            <template
              v-for="(item,index) in getTableSlot()"
              #[item.tableName]="props">
              <slot :key="item.name+index" :name="item.name" v-bind="props"></slot>
            </template>
          </DynamicTable>
        </div>
        <div class="right">
          <DynamicTable
            :data="filterSelectData"
            :height="listHeight"
            :table-config-list="computedTableConfigList"
            :created-init-value="false"
            ref="rightTableRef"
            @select-change-event="rightSelectChangeEvent"
            @row-update-event="rightRowUpdateEvent"
          >
            <template
              v-for="(item,index) in getTableSlot()"
              #[item.tableName]="props">
              <slot :key="item.name+index" :name="item.name" v-bind="props"></slot>
            </template>
          </DynamicTable>
        </div>
      </div>
    </template>
  </ListPage>
</template>

<script lang="ts">
import SelectObjectMixin2 from "../../mixins/SelectObjectMixin2";
import ListPage from "../ListPage/index.vue";
import {PropType} from "vue";
import {SearchListFunc, SearchListParams} from "../ListPage/type";
import DynamicForm from "../DynamicForm3/index.vue";
import {FormConfigItem} from "../DynamicForm3/types";
import DynamicTable from "../DynamicTable3/index.vue";
import {EventFirstParam, TableConfigItem, TableEventFirstParam} from "../DynamicTable3/types";
import {DyTableUtils} from "../DynamicTable3/Utils";

/**
 * 外部元素一定要有一个固定的高度
 * 表格选择
 * 分两个表格并列，
 * 右边是获取数据
 * 左边是选中的数据
 */
export default {
  name: "TableSelect",
  props: {
    modelValue:{
      type: Array,
      default: []
    },
    rowKey: {
      type: String,
      default: 'id'
    },
    /**
     * 远程搜索方法
     */
    searchList: {
      type: Function as PropType<SearchListFunc>,
      default:()=>Promise.resolve({
        list: [],
        total: 0,
      })
    },
    formConfigList: {
      type:Array as PropType<FormConfigItem[]>,
      default: []
    },
    rightFilterField: { // 右边过滤字段，直接使用searchData里面的值
      type:String,
      default: ''
    },
    tableConfigList: {
      type: Array as PropType<TableConfigItem[]>
    },
    useSelect: { // 使用选择
      type: Boolean,
      default: false,
    },
    multipleSelect: { // 多选
      type: Boolean,
      default: true,
    }
  },
  components: {DynamicTable, DynamicForm, ListPage},
  emits:['update:modelValue'],
  mixins:[SelectObjectMixin2],
  watch: {
    modelValue: {
      immediate: true,
      handler(val = []) {
        this.selectData = val
        this.selectData2TableData()
      }
    },
    selectData(val=[]) {
      this.$emit('update:modelValue',val)
    },
    "filterSelectData.length": {
      handler() {
        this.rightTableIsSelectAll()
      }
    },
    filterSelectData() {
      this.rightTableIsSelectAll()
    }
  },
  computed: {
    filterSelectData() {
      if(this.multipleSelect) {
        if(this.rightFilterField) {
          if(this.searchData[this.rightFilterField]) {
            return this.selectData.filter((i)=>{
              return String(i[this.rightFilterField])
                .includes(String(this.searchData[this.rightFilterField]))
            })
          }
        }
      }
      return this.selectData
    },
    computedTableConfigList() {
      let result = []
      if(this.useSelect) {
        if(this.multipleSelect) {
          result.push({
            type: 'selection',
            width: '55'
          })
        } else {
          result.push({
            type: 'radio',
            width: '55'
          })
        }
      }
      result.push(...this.tableConfigList)
      return result
    }
  },
  data() {
    return {
      searchData: {},
      clearScollXFunc:null
    }
  },
  mounted() {
    this.clearScollXFunc = DyTableUtils.multipleTableScrollX([
      this.$refs.leftTableRef,
      this.$refs.rightTableRef
    ])
  },
  beforeUnmount() {
    if(this.clearScollXFunc) {
      this.clearScollXFunc()
    }
  },
  methods: {
    treeSelectSearchList(search:SearchListParams) {
      return new Promise((resolve, reject) => {
        this.searchList(search)
          .then(res => {
            resolve(res)
          })
          .catch(err => {
            reject(err)
          })
          .finally(() => {
            this.$nextTick(() => {
              this.selectData2TableData()
            })
          })
      })
    },
    async reset() {
      await this.$refs.DynamicFormRef.resetFields()
      this.$refs.ListPageRef.getList()
    },
    getTableListData(listData) {
      this.tableData = listData
      return this.tableData
    },
    getTableSlot() {
      let start = 'table_'
      return Object.keys(this.$slots).filter(i=>{
        return i.startsWith(start);
      }).map(i=>{
        return {
          name: i,
          tableName: i.substring(i.indexOf(start) + start.length)
        }
      })
    },
    /**
     * 右边的表格始终是一个选中的状态
     */
    rightTableIsSelectAll() {
      if(this.useSelect){
        this.$nextTick(()=>{
          this.filterSelectData.forEach(i=>{
            this.$refs.rightTableRef.toggleRowSelection(i,true)
          })
        })
      }
    },
    tableDataEqualsSelectData(tableItem: any, selectItem: any) {
      return tableItem[this.rowKey] === selectItem[this.rowKey];
    },
    tableDataIsSelectCall(tableItem, tableIndex, selected) {
      if(this.useSelect){
        this.$refs.leftTableRef.toggleRowSelection(tableItem,selected)
      }
    },
    leftSelectChangeEvent(params: TableEventFirstParam,selection: any[]) {
      this.addTableData2SelectData(params.addSelect)
      this.clearTableData2SelectData(params.removeSelect)
    },
    leftRowUpdateEvent(params: EventFirstParam) {
      this.tableRowUpdate(params.row,params.$index)
    },
    rightSelectChangeEvent(params: TableEventFirstParam,selection: any[]) {
      this.clearSelectData2TableData(params.removeSelect)
    },
    rightRowUpdateEvent(params: EventFirstParam){
      this.selectRowUpdate(params.row,params.$index)
    },
    /**
     * 如果组件进行派生，这个就是要重写的
     * @param tableItem
     * @param tableIndex
     * @param selectItem
     * @param selectIndex
     */
    selectRowUpdateCall(tableItem: any | null, tableIndex: number, selectItem: any, selectIndex: number) {
      if(tableItem) {
        Object.assign(tableItem,selectItem)
      }
    },
    /**
     * 如果组件进行派生，这个就是要重写的
     * @param selectItem
     * @param selectIndex
     * @param tableItem
     * @param tableIndex
     */
    tableRowUpdateCall(selectItem: any | null, selectIndex: number, tableItem: any, tableIndex: number) {
      if(selectItem) {
        Object.assign(selectItem,tableItem)
      } else {
        this.addTableRow2SelectData(tableItem)
      }
    },
  }
}
</script>

<style lang="scss" scoped>
.TableSelect{
  display: flex;
  height: 100%;
  &>div{
    width: 50% !important;
    height: 100% !important;
    flex-shrink: 0 !important;
  }
  .left {
    border-right: 1px solid blue;
    padding-right: 10px;
  }
  .right {
    border-left: 1px solid blue;
    padding-left: 10px;
  }
}
</style>
